package com.hub.realtime.flinkshims.core;


import lombok.Getter;

import java.util.Optional;
import java.util.function.Function;
import java.util.regex.Pattern;


@Getter
public enum SqlCommand {

    //todo -----------create语句--------

    /**
     * CREATE CATALOG catalog_name
     * WITH (key1=val1, key2=val2, ...)
     */
    CREATE_CATALOG(
            "create catalog",
            "(CREATE\\s+CATALOG.*)",
            (operands) -> Optional.of(new String[]{operands[0]})),

    /**
     * <pre>
     * CREATE DATABASE [IF NOT EXISTS] [catalog_name.]db_name<br>
     * [COMMENT database_comment]<br>
     * WITH (key1=val1, key2=val2, ...)<br>
     * </pre>
     */
    CREATE_DATABASE(
            "create database",
            "(CREATE\\s+DATABASE\\s+.*)",
            (operands) -> Optional.of(new String[]{operands[0]})),


    /**
     * <pre>
     * CREATE TABLE [IF NOT EXISTS] [catalog_name.][db_name.]table_name
     * (
     * { <physical_column_definition> | <metadata_column_definition> | <computed_column_definition> }[ , ...n]
     * [ <watermark_definition> ]
     * [ <table_constraint> ][ , ...n]
     * )
     * [COMMENT table_comment]
     * [PARTITIONED BY (partition_column_name1, partition_column_name2, ...)]
     * WITH (key1=val1, key2=val2, ...)
     * [ LIKE source_table [( <like_options> )] ]
     * </pre
     */
    CREATE_TABLE(
            "create table",
            "(CREATE\\s+(TEMPORARY\\s+|)TABLE\\s+.*)",
            (operands) -> Optional.of(new String[]{operands[0]})),

    /**
     * <pre>
     * CREATE [TEMPORARY] VIEW [IF NOT EXISTS] [catalog_name.][db_name.]view_name
     * [( columnName [, columnName ]* )] [COMMENT view_comment]
     * AS query_expression<
     * </pre
     */
    CREATE_VIEW(
            "create view",
            "CREATE\\s+(TEMPORARY\\s+|)VIEW\\s+(\\S+)\\s+AS\\s+(.*)",
            (operands) -> {
                if (operands.length < 2) return Optional.empty();
                else return Optional.of(new String[]{operands[0], operands[1]});
            }
    ),


    /**
     * <pre>
     * CREATE [TEMPORARY|TEMPORARY SYSTEM] FUNCTION
     * [IF NOT EXISTS] [catalog_name.][db_name.]function_name
     * AS identifier [LANGUAGE JAVA|SCALA|PYTHON]
     * </pre
     */
    CREATE_FUNCTION(
            "create function",
            "(CREATE\\s+(TEMPORARY\\s+|TEMPORARY\\s+SYSTEM\\s+|)FUNCTION\\s+.*)",
            (operands) -> Optional.of(new String[]{operands[0]})),


    //todo ----ALTER Statements ---

    ALTER_DATABASE(
            "alert database",
            "(ALTER\\s+DATABASE\\s+.*)",
            (operands) -> Optional.of(new String[]{operands[0]})),

    ALTER_TABLE(
            "alert table",
            "(ALTER\\s+TABLE\\s+.*)",
            (operands) -> Optional.of(new String[]{operands[0]})),

    ALTER_FUNCTION(
            "alert function",
            "(ALTER\\s+FUNCTION.*)",
            (operands) -> Optional.of(new String[]{operands[0]})),


    //todo ----DROP Statements----

    DROP_CATALOG(
            "drop catalog",
            "(DROP\\s+CATALOG\\s+.*)",
            (operands) -> Optional.of(new String[]{operands[0]})),

    DROP_DATABASE(
            "drop database",
            "(DROP\\s+DATABASE\\s+.*)",
            (operands) -> Optional.of(new String[]{operands[0]})),

    DROP_TABLE(
            "drop table",
            "(DROP\\s+TABLE\\s+.*)",
            (operands) -> Optional.of(new String[]{operands[0]})),


    DROP_VIEW(
            "drop view",
            "DROP\\s+VIEW\\s+(.*)",
            (operands) -> Optional.of(new String[]{operands[0]})),

    DROP_FUNCTION(
            "drop function",
            "DROP\\s+FUNCTION\\s+(.*)",
            (operands) -> Optional.of(new String[]{operands[0]})),


    //todo ----SHOW Statements ---

    SHOW_CATALOGS(
            "show catalogs",
            "SHOW\\s+CATALOGS",
            (operands) -> Optional.of(new String[]{"SHOW CATALOGS"})),

    SHOW_CURRENT_CATALOG(
            "show current catalogs",
            "SHOW\\s+CURRENT\\s+CATALOG",
            (operands) -> Optional.of(new String[]{"SHOW CURRENT CATALOGS"})),


    SHOW_DATABASES(
            "show database",
            "SHOW\\s+DATABASES",
            (operands) -> Optional.of(new String[]{"SHOW DATABASES"})),


    SHOW_CURRENT_DATABASE(
            "show current database",
            "SHOW\\s+CURRENT\\s+DATABASE",
            (operands) -> Optional.of(new String[]{"SHOW CURRENT DATABASES"})),


    SHOW_TABLES(
            "show tables",
            "SHOW\\s+TABLES",
            (operands) -> Optional.of(new String[]{"SHOW TABLES"})),

    SHOW_VIEWS(
            "show views",
            "SHOW\\s+VIEWS",
            (operands) -> Optional.of(new String[]{"SHOW VIEWS"})),


    SHOW_FUNCTIONS(
            "show functions",
            "SHOW\\s+FUNCTIONS",
            (operands) -> Optional.of(new String[]{"SHOW FUNCTIONS"})),


    SHOW_MODULES(
            "show modules",
            "SHOW\\s+MODULES",
            (operands) -> Optional.of(new String[]{"SHOW MODULES"})),

    //todo ---- INSERT Statement #


    INSERT_INTO(
            "insert into",
            "(INSERT\\s+INTO.*)",
            (operands) -> Optional.of(new String[]{operands[0]})),

    INSERT_OVERWRITE(
            "insert overwrite",
            "(INSERT\\s+OVERWRITE.*)",
            (operands) -> Optional.of(new String[]{operands[0]})),


    //todo ---- SELECT Statements #

    SELECT(
            "select",
            "(WITH.*SELECT.*|SELECT.*)",
            (operands) -> Optional.of(new String[]{operands[0]})),


    //todo ---- USE Statements #

    USE_CATALOG(
            "use catalog",
            "USE\\s+CATALOG\\s+(.*)",
            (operands) -> Optional.of(new String[]{operands[0]})),


    USE(
            "use",
            "USE\\s+(?!CATALOG)(.*)",
            (operands) -> Optional.of(new String[]{operands[0]})),


    DESC(
            "describe",
            "DESC\\s+(.*)",
            (operands) -> Optional.of(new String[]{operands[0]})),


    DESCRIBE(
            "desc",
            "DESCRIBE\\s+(.*)",
            (operands) -> Optional.of(new String[]{operands[0]})),


    /**
     * <pre>
     * EXPLAIN PLAN FOR <query_statement_or_insert_statement>
     * </pre>
     */
    EXPLAIN(
            "explain plan for",
            "(EXPLAIN\\s+PLAN\\s+FOR\\s+(SELECT\\s+.*|INSERT\\s+.*))",
            (operands) -> Optional.of(new String[]{operands[0]})),


    SET(
            "set",
            "SET(\\s+(\\S+)\\s*=(.*))?",
            (operands) -> {
                if (operands.length >= 3) {
                    if (operands[0] == null) {
                        return Optional.of(new String[0]);
                    }
                } else {
                    return Optional.empty();
                }
                return Optional.of(new String[]{operands[1], operands[2]});
            }),

    RESET(
            "reset",
            "RESET\\s*(.*)",
            (operands) -> {
                if (operands[0] != null) {
                    return Optional.of(new String[]{operands[0]});
                } else {
                    return Optional.of(new String[]{"ALL"});
                }
            });



    private final String name;

    public final Pattern pattern;

    public final Function<String[], Optional<String[]>> operandConverter;

    SqlCommand(String name, String matchingRegex, Function<String[], Optional<String[]>> operandConverter) {
        this.name = name;
        pattern = Pattern.compile(matchingRegex, Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
        this.operandConverter = operandConverter;

    }



}
